﻿#region --- License & Copyright Notice ---
/*
ConsoleFx CommandLine Processing Library

Copyright (c) 2006-2012 Jeevan James
All rights reserved.

The contents of this file are made available under the terms of the
Eclipse Public License v1.0 (the "License") which accompanies this
distribution, and is available at the following URL:
http://opensource.org/licenses/eclipse-1.0.txt

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.

By using this software in any fashion, you are agreeing to be bound by the
terms of the License.
*/
#endregion

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace ConsoleFx.Programs.Interactive
{
    internal sealed class RegisteredCommand
    {
        private readonly Type _type;
        private readonly Func<CommandBase> _factory;
        private readonly string _name;
        private readonly string _shortName;
        private readonly string _description;

        internal RegisteredCommand(Type type, Func<CommandBase> factory = null)
        {
            _type = type;
            _factory = factory;

            string commandName = _type.Name;
            if (commandName.EndsWith("Command", StringComparison.OrdinalIgnoreCase))
                _name = commandName.Substring(0, commandName.Length - "Command".Length);
            else
                _name = commandName;

            object[] commandAttributes = _type.GetCustomAttributes(typeof(CommandAttribute), false);
            if (commandAttributes.Length > 0)
            {
                var commandAttribute = (CommandAttribute)commandAttributes[0];
                if (!string.IsNullOrWhiteSpace(commandAttribute.Name))
                    _name = commandAttribute.Name;
                if (!string.IsNullOrWhiteSpace(commandAttribute.ShortName))
                    _shortName = commandAttribute.ShortName;
                _description = commandAttribute.Description;
            }
        }

        internal Type Type
        {
            get { return _type; }
        }

        internal Func<CommandBase> Factory
        {
            get { return _factory; }
        }

        public string Name
        {
            get { return _name; }
        }

        public string ShortName
        {
            get { return _shortName; }
        }

        public string Description
        {
            get { return _description; }
        }
    }

    internal sealed class RegisteredCommandCollection : KeyedCollection<Type, RegisteredCommand>
    {
        internal void Add<T>(Func<T> factory = null)
            where T : CommandBase
        {
            Add(new RegisteredCommand(typeof(T), factory));
        }

        internal void Add(Type commandType, Func<CommandBase> factory = null)
        {
            Add(new RegisteredCommand(commandType, factory));
        }

        internal void AddRange(IEnumerable<Type> commands)
        {
            foreach (Type command in commands)
                Add(new RegisteredCommand(command));
        }

        internal RegisteredCommand this[string str]
        {
            get
            {
                return
                    this.FirstOrDefault(
                        rc =>
                            rc.Name.Equals(str, StringComparison.OrdinalIgnoreCase) ||
                                (!string.IsNullOrEmpty(rc.ShortName) && rc.ShortName.Equals(str, StringComparison.OrdinalIgnoreCase)));
            }
        }

        protected override Type GetKeyForItem(RegisteredCommand item)
        {
            return item.Type;
        }
    }
}